﻿using MyCrawler.Entity;
using MyCrawler.Utilyties;
using System;
using System.Collections.Generic;
using System.IO;
using Spider.Framework.UtilityCommon.Extensions;
using System.Text;
using System.Net;
using System.Text.RegularExpressions;
using System.Threading;
using Spider.Framework.Download;

namespace MyCrawler.Controls
{
    public class ForumsCtr
    {
        public string _source;
        public string _domain;
        public string _linkInit;

        public int _pageLimit; // số trang giới hạn
        public DateTime _dtLimit; // giới hạn ngày lấy, những bài có update cũ hơn ngày này thi bỏ qua

        public string _timeStart;
        public int _totalTopic;
        public string _blockId;

        public void RunCrawler()
        {
            try
            {
                //GetTopics();
                //return;

                TraceLog_Status(_source, _blockId, " -- Start at " + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss tt") + " -- ");

                #region làm việc với ngày giới hạn
                // đọc thời gian limit từ file txt
                string sDateLast = UtilityCtr.ReadSettingTime(_source).Replace("\r\n", "").Trim();
                if (sDateLast == "") // không có ghi nhận lần chạy gần nhất
                {
                    _dtLimit = DateTime.Now.AddDays(-365); // lấy giới hạn trong vòng 60 ngày
                }
                else
                {
                    _dtLimit = Convert.ToDateTime(sDateLast); // ngày giới hạn là ngày quét gần nhất được lưu lại trong file txt
                }

                // ghi nhận lại thời gian chạy mới
                DateTime dtNow = DateTime.Now;
                _blockId = dtNow.ToString("yyyyMMddhhmmss");
                _timeStart = dtNow.ToString("yyyy-MM-dd hh:mm:ss"); // thời điểm khởi chạy
                _totalTopic = 0; // số topic đã lấy

                UtilityCtr.TraceSettingTime(_source, _timeStart, 0, _dtLimit.ToString("yyyy-MM-dd hh:mm:ss tt"));
                #endregion

                GetTopics();

                TraceLog_Status(_source, _blockId, " -- Finished at " + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss tt") + " -- ");
            }
            catch (Exception ex)
            {
                TraceLog_Status(_source, _blockId, "Start error: " + ex.Message); // ghi log để test
            }
        }

        /// <summary>
        /// Chạy lại từ đầu của 1 block
        /// </summary>
        /// <param name="sDateLast"></param>
        /// <param name="blockId"></param>
        public void ReRunCrawler(string dateLast, string blockId)
        {
            try
            {
                _dtLimit = Convert.ToDateTime(dateLast); // ngày giới hạn là ngày quét gần nhất được lưu lại trong file txt
                _timeStart = dateLast;
                _blockId = blockId;

                TraceLog_Status(_source, _blockId, " ");
                TraceLog_Status(_source, _blockId, " ");
                TraceLog_Status(_source, _blockId, " ");
                TraceLog_Status(_source, _blockId, " ");
                TraceLog_Status(_source, _blockId, "Re ------------------------------------------------------------------------------------------");

                GetTopics();

                TraceLog_Status(_source, _blockId, " -- Finished at " + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss tt") + "-- ");
            }
            catch (Exception ex)
            {
                TraceLog_Status(_source, _blockId, "Mothod ReRunCrawler() lỗi: " + ex.Message); // ghi log để test
            }
        }

        /// <summary>
        /// tiếp tục chạy của 1 block, dựa trên thời gian gần nhất của chủ đề
        /// </summary>
        /// <param name="linkCata"></param>
        /// <param name="lastCrawl">thời gian khởi chạy</param>
        /// <param name="blockId"></param>
        public void ContinueRunCrawler(string lnkCat, string lastCrawl, string blockId)
        {
            try
            {
                _dtLimit = Convert.ToDateTime(UtilityCtr.ReadLastCrawl(_source)); // ngày giới hạn là ngày quét gần nhất được lưu lại trong file txt
                _timeStart = lastCrawl;
                _blockId = blockId;

                // lấy các link của catagories trong 1 file json
                CatagoriesToRunEntity cat = UtilityCtr.ReadLinkCatagoriesFromJson(_source);

                if (cat != null)
                {
                    List<string> ls = cat.LsLink;
                    if (ls != null && ls.Count > 0)
                    {
                        for (int i = 0; i < ls.Count; i++)
                        {
                            int index = ls.IndexOf(lnkCat);

                            if (index > -1)
                            {
                                List<string> lsSub = ls.GetRange(index, ls.Count - index);

                                for (int j = 0; j < lsSub.Count; j++)
                                {
                                    GetListTopic_InCatagory(lsSub[j]);
                                }
                            }
                        }
                    }
                }

                TraceLog_Status(_source, _blockId, " -- Finished at " + DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss tt") + "-- ");
            }
            catch (Exception ex)
            {
                TraceLog_Status(_source, _blockId, "Mothod ContinueRunCrawler() lỗi: " + ex.Message); // ghi log để test
            }
        }

        public void GetTopics()
        {
            try
            {
                // lấy các link của catagories trong 1 file json
                CatagoriesToRunEntity cat = UtilityCtr.ReadLinkCatagoriesFromJson(_source);

                List<string> ls = new List<string>();
                if (cat != null)
                {
                    try
                    {
                        DateTime dtUpdate = Convert.ToDateTime(cat.DateStart);

                        // nếu ngày cập nhật quá 30 ngày thực hiện cập nhật mới - có thể họ tạo hay sửa các catagories
                        TimeSpan ts = DateTime.Now.Subtract(dtUpdate);
                        int day = ts.Days;

                        if (day > 30)
                        {
                            #region lấy danh sách link và ghi file json mới
                            ls = GetCatalogByLink();

                            if (ls != null && ls.Count > 0)
                            {
                                cat.DateStart = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
                                cat.LsLink = ls;

                                // ghi các link danh mục này vào file Json
                                UtilityCtr.WriteLinkCatagoriesToJson(_source, cat);
                            }
                            #endregion
                        }
                        else
                        {
                            ls = cat.LsLink;
                        }
                    }
                    catch { }
                }
                else
                {
                    #region lấy danh sách link và ghi file json mới
                    ls = GetCatalogByLink();

                    if (ls != null && ls.Count > 0)
                    {
                        cat = new CatagoriesToRunEntity();
                        cat.DateStart = DateTime.Now.ToString("yyyy-MM-dd hh:mm:ss");
                        cat.LsLink = ls;

                        // ghi các link danh mục này vào file Json
                        UtilityCtr.WriteLinkCatagoriesToJson(_source, cat);
                    }
                    #endregion
                }

                if (ls.Count > 0)
                {
                    for (int i = 0; i < ls.Count; i++)
                    {
                        GetListTopic_InCatagory(ls[i]);
                    }
                }
                else
                {
                    TraceLog_Status(_source, _blockId, "Data empty");
                }
            }
            catch (Exception ex)
            {
                TraceLog_Status(_source, _blockId, "Get Topics error: " + ex.Message);
            }
        }

        public virtual List<string> GetCatalogByLink() { return null; }

        public virtual void GetListTopic_InCatagory(string lnk) { }

        public string LogFileJson(ContentEntity entity)
        {
            try
            {
                string mes = "";
                var folder = Config.FTP_FOLDER + "/" + entity.Source + "/" + entity.LastModify.ToString("ddMMyyyy");
                if (!Directory.Exists(folder)) Directory.CreateDirectory(folder);
                var file = folder + "/" + entity.Id + entity.LastModify.ToUnixTimestamp() + ".txt";

                if (File.Exists(file))
                {
                    mes = file + ", file existed";
                    return mes;
                }

                var sw = new StreamWriter(file);
                sw.Write(entity.ToJson());
                sw.Close();

                /* Tạm tắt, chạy thật mới bật lên 
                if (File.Exists(file))
                {
                    FtpExpress ftp = new FtpExpress(Config.FTP_ADDRESS, Config.FTP_USER, Config.FTP_PASSWORD);
                    bool re = ftp.Upload(file, file, false);

                    if (re == true)
                    {
                        mes = file + ", created new & upload success";
                    }
                    else
                    {
                        mes = file + ", created new & upload false";
                    }
                }
                */
                return mes;
            }
            catch (Exception ex)
            {
                return "error: " + ex.Message;
            }
        }

        /// <summary>
        /// Ghi trạng thái
        /// </summary>
        /// <param name="source"></param>
        /// <param name="blockid"></param>
        /// <param name="message"></param>
        public void TraceLog_Status(string source, string blockid, string message)
        {
            try
            {
                string pathFolder = @"C:\ToanCrawlerLogs\" + source;
                if (!Directory.Exists(pathFolder))
                {
                    Directory.CreateDirectory(pathFolder);
                }

                #region Kiểm tra và tạo thư mục theo source

                string pattFull = @"C:\ToanCrawlerLogs\" + source + @"\Status";

                if (!Directory.Exists(pattFull))
                {
                    Directory.CreateDirectory(pattFull);
                }
                #endregion

                #region làm việc với file
                // tạo file log nếu chưa tồn tại, file có dạng: nguon_link_trangthaicoloikhong.txt
                string sFile = blockid + ".txt";

                string pathFile = pattFull + "/" + sFile;

                if (!File.Exists(pathFile))
                {
                    File.Create(pathFile).Dispose();
                }
                #endregion

                #region Thực hiện ghi file

                FileStream fsObj = new FileStream(pathFile, FileMode.Append);
                StreamWriter swObj = new StreamWriter(fsObj, Encoding.UTF8);

                // Ghi từng dòng
                swObj.WriteLine(message);

                swObj.Flush();

                swObj.Close();
                fsObj.Close();

                #endregion
            }
            catch (Exception ex) { }
        }

        /// <summary>
        /// Lấy nội dung Html theo dạng DownloadData
        /// </summary>
        /// <param name="url">url ex: http://domain.com</param>
        /// <param name="timeDelay">thời gian nghỉ trước khi gửi request (đv: mili giây), dùng để tránh web owner nhận biết mình crawler liên tục</param>
        /// <returns></returns>
        public string GetWebContent(string url, int timeDelay)
        {
            string s = "";
            try
            {
                if (timeDelay > 0) // nếu có thiết lập thời gian chờ
                {
                    Thread.Sleep(timeDelay);
                }

                WebClient client = new WebClient();
                client.Encoding = Encoding.UTF8;
                client.Headers.Add("user-agent", "Mozilla/4.0 (compatible; MSIE 6.0; Windows NT 5.2; .NET CLR 1.0.3705;)");

                s = Encoding.UTF8.GetString(client.DownloadData(url));

                s = s.Replace("\r", "").Replace("\n", "").Replace("\t", "").Replace("\"", "'"); // xóa \r\n\t và \" thành dấu nháy đơn
                s = Regex.Replace(s, @"[\s]{2,}", " "); // xóa nhiều khoảng trắng

            }
            catch (Exception ex) { }
            return s;
        }

        /// <summary>
        /// Lấy nội dung Html theo dạng StreamReader
        /// </summary>
        /// <param name="url">url ex: http://domain.com</param>
        /// <param name="timeDelay">thời gian nghỉ trước khi gửi request (đv: mili giây), dùng để tránh web owner nhận biết mình crawler liên tục</param>
        /// <returns></returns>
        public string GetContentWithStream(string url, int timeDelay)
        {
            string s = "";
            try
            {
                if (timeDelay > 0) // nếu có thiết lập thời gian chờ
                {
                    Thread.Sleep(timeDelay);
                }

                using (WebClient client = new WebClient())
                {
                    client.Headers.Add("Accept: text/html, application/xhtml+xml, */*");
                    client.Headers.Add("user-agent", " Mozilla/5.0 (Windows NT 6.1; WOW64; rv:25.0) Gecko/20100101 Firefox/29.0.1");
                    client.Headers.Add("Accept-Language", "en-gb,en;q=0.5");
                    client.Headers.Add("Accept-Charset", "ISO-8859-1,utf-8;q=0.7,*;q=0.7");
                    client.Encoding = System.Text.Encoding.UTF8;

                    using (Stream data = client.OpenRead(url))
                    {
                        using (StreamReader reader = new StreamReader(data))
                        {
                            s = reader.ReadToEnd();

                            s = s.Replace("\r", "").Replace("\n", "").Replace("\t", "").Replace("\"", "'"); // xóa \r\n\t và \" thành dấu nháy đơn
                            s = Regex.Replace(s, @"[\s]{2,}", " "); // xóa nhiều khoảng trắng
                        }
                    }
                }
            }
            catch (Exception ex) { }
            return s;
        }

        /// <summary>
        /// Lấy nội dung Html theo dạng DownloadString, không mã hóa
        /// </summary>
        /// <param name="url">url ex: http://domain.com</param>
        /// <param name="timeDelay">thời gian nghỉ trước khi gửi request (đv: mili giây), dùng để tránh web owner nhận biết mình crawler liên tục</param>
        /// <returns></returns>
        public string GetHtmlByDownloadStringNonEnCoding(string url, int timeDelay)
        {
            string s = "";
            try
            {
                if (timeDelay > 0) // nếu có thiết lập thời gian chờ
                {
                    Thread.Sleep(timeDelay);
                }

                using (WebClient wClient = new WebClient())
                {
                    s = wClient.DownloadString(url);

                    s = s.Replace("\r", "").Replace("\n", "").Replace("\t", "").Replace("\"", "'"); // xóa \r\n\t và \" thành dấu nháy đơn
                    s = Regex.Replace(s, @"[\s]{2,}", " "); // xóa nhiều khoảng trắng
                }
            }
            catch (Exception ex) { }
            return s;
        }
    }
}
